package com.linkoog.devtools.type.javadoc;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.linkoog.devtools.utils.StringUtils;
import org.apache.commons.collections.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JavaDocParser {

    public static JavaDoc parse(PsiDocComment psiDocComment){
        if (psiDocComment == null){
            return null;
        }

        JavaDoc javaDoc = new JavaDoc();
        javaDoc.setContext(parseContext(psiDocComment));
        javaDoc.setTagComments(parseTags(psiDocComment));

        String description = findDescriptionByJavaComment(javaDoc.getTagComments());
        if (StringUtils.isBlank(description)){
            description = findDescriptionByDocContext(javaDoc.getContext());
        }

        if (StringUtils.isBlank(description)){
            description = "";
        }
        javaDoc.setDescription(description);
        return javaDoc;
    }

    /**
     *   解析body内容
     */
    private static String parseContext(PsiDocComment psiDocComment) {
        StringBuilder commentDescription = new StringBuilder();
        PsiElement[] descriptionElements = psiDocComment.getDescriptionElements();
        for (PsiElement psiElement : descriptionElements) {
            if (psiElement instanceof PsiWhiteSpace){
                continue;
            }
            String text = psiElement.getText().trim();
            if (!text.equals("\n")){
                commentDescription.append(text);
            }
        }
        return commentDescription.toString();
    }

    /**
     *   解析tags内容
     */
    private static List<JavaComment> parseTags(PsiDocComment psiDocComment){
        return ApplicationManager.getApplication().runReadAction((Computable<List<JavaComment>>) ()-> {
            PsiDocTag[] psiDocTags = psiDocComment.getTags();
            List<JavaComment> comments = new ArrayList<>();
            for (PsiDocTag psiDocTag : psiDocTags) {
                String tagName = psiDocTag.getName();
                if (StringUtils.isBlank(tagName) ) continue;
                if (tagName.endsWith(":")){
                    tagName = tagName.substring(0, tagName.length() - 1);
                }

                PsiElement[] psiElements = psiDocTag.getDataElements();
                if (psiElements.length == 0){
                    comments.add(new JavaComment(tagName, null, ""));
                } else if (psiElements.length == 1){
                    String key = psiElements[0].getText();
                    if (key != null && key.startsWith(":")){
                        key = key.substring(1).trim();
                    }
                    comments.add(new JavaComment(tagName, null, key));
                } else {
                    if ("return".equalsIgnoreCase(tagName)){
                        comments.add(new JavaComment(tagName, null, buildPsiElementText(psiElements)));
                    } else if ("param".equalsIgnoreCase(tagName)){
                        String key = psiElements[0].getText();
                        if (key != null && key.startsWith(":")){
                            key = key.substring(1).trim();
                        }
                        comments.add(new JavaComment(tagName, key, buildPsiElementText(psiElements)));
                    } else {
                        String key = psiElements[0].getText();
                        if (key != null && key.startsWith(":")){
                            key = key.substring(1).trim();
                        }

                        PsiElement[] valElements = new PsiElement[psiElements.length - 1];
                        System.arraycopy(psiElements,1, valElements, 0, psiElements.length - 1);
                        String value = buildPsiElementText(valElements);
                        if (StringUtils.isNotBlank(value)){
                            comments.add(new JavaComment(tagName, key, value));
                        } else {
                            comments.add(new JavaComment(tagName,null, key));
                        }
                    }
                }
            }

            return comments;
        });
    }

    private static String buildPsiElementText(PsiElement[] psiElements){
        StringBuilder valueBuilder = new StringBuilder();
        for (int i = 1; i < psiElements.length; i++) {
            String text = psiElements[i].getText();
            valueBuilder.append(text);
            if (i != psiElements.length - 1){
                valueBuilder.append("\n");
            }
        }
        return valueBuilder.toString();
    }

    private static String findDescriptionByJavaComment(List<JavaComment> javaComments){
        if (CollectionUtils.isNotEmpty(javaComments)) return null;
        for (JavaComment javaComment : javaComments) {
            if ("description".equalsIgnoreCase(javaComment.getName())
                    ||  "desc".equalsIgnoreCase(javaComment.getName())
                    ||  "remark".equalsIgnoreCase(javaComment.getName())){
                return javaComment.getValue();
            }
        }
        return null;
    }

    private static String findDescriptionByDocContext(String docContext){
        if (StringUtils.isNotBlank(docContext)){
            docContext = docContext.trim();
            //去除<p>的前后缀
            docContext = StringUtils.removePrefix(docContext,"<p>");
            docContext = StringUtils.removeSuffix(docContext,"</p>");
            docContext = StringUtils.removeSuffix(docContext,"<p>");
            //去除<pre>的前后缀
            docContext = StringUtils.removePrefix(docContext,"<pre>");
            docContext = StringUtils.removeSuffix(docContext,"</pre>");
            docContext = StringUtils.removeSuffix(docContext,"<pre>");

            if (StringUtils.isNotBlank(docContext)) docContext = docContext.trim();
            docContext = StringUtils.removePrefix(docContext,"Description:");
            docContext = StringUtils.removePrefix(docContext,"description:");
            return docContext;
        }
        return null;
    }


}
